From 4b6d60a8f0edb4181e28eadb01ffee9adefc7640 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 9 Nov 2005 14:39:32 +0100 Subject: [PATCH] Allow xen_create_contiguous_region() to fail gracefully if it cannot allocate a contiguous multi-page extent of memory. This should avoid unnecessary crashes in the xen-specific skbuff cache constructor. Signed-off-by: Keir Fraser --- .../arch/xen/i386/kernel/pci-dma.c | 7 ++-- .../arch/xen/i386/kernel/swiotlb.c | 7 ++-- .../arch/xen/i386/mm/hypervisor.c | 32 ++++++++++++++++--- .../arch/xen/i386/mm/pgtable.c | 5 +-- linux-2.6-xen-sparse/arch/xen/kernel/skbuff.c | 4 ++- .../include/asm-xen/asm-i386/hypervisor.h | 7 ++-- 6 files changed, 49 insertions(+), 13 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/pci-dma.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/pci-dma.c index b126438f1c..27736142ed 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/pci-dma.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/pci-dma.c @@ -152,8 +152,11 @@ void *dma_alloc_coherent(struct device *dev, size_t size, ret = (void *)vstart; if (ret != NULL) { - xen_create_contiguous_region(vstart, order); - + /* NB. Hardcode 31 address bits for now: aacraid limitation. */ + if (xen_create_contiguous_region(vstart, order, 31) != 0) { + free_pages(vstart, order); + return NULL; + } memset(ret, 0, size); *dma_handle = virt_to_bus(ret); } diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c index 54945eb4a9..e2a14d1688 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c @@ -117,6 +117,7 @@ void swiotlb_init_with_default_size (size_t default_size) { unsigned long i, bytes; + int rc; if (!iotlb_nslabs) { iotlb_nslabs = (default_size >> IO_TLB_SHIFT); @@ -137,8 +138,10 @@ swiotlb_init_with_default_size (size_t default_size) "Use dom0_mem Xen boot parameter to reserve\n" "some DMA memory (e.g., dom0_mem=-128M).\n"); - xen_create_contiguous_region( - (unsigned long)iotlb_virt_start, get_order(bytes)); + /* Hardcode 31 address bits for now: aacraid limitation. */ + rc = xen_create_contiguous_region( + (unsigned long)iotlb_virt_start, get_order(bytes), 31); + BUG_ON(rc); /* * Allocate and initialize the free list array. This array is used diff --git a/linux-2.6-xen-sparse/arch/xen/i386/mm/hypervisor.c b/linux-2.6-xen-sparse/arch/xen/i386/mm/hypervisor.c index a30d64f876..a48ff231d0 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/mm/hypervisor.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/mm/hypervisor.c @@ -314,7 +314,8 @@ static void contiguous_bitmap_clear( } /* Ensure multi-page extents are contiguous in machine memory. */ -void xen_create_contiguous_region(unsigned long vstart, unsigned int order) +int xen_create_contiguous_region( + unsigned long vstart, unsigned int order, unsigned int address_bits) { pgd_t *pgd; pud_t *pud; @@ -349,9 +350,10 @@ void xen_create_contiguous_region(unsigned long vstart, unsigned int order) /* 2. Get a new contiguous memory extent. */ reservation.extent_order = order; - reservation.address_bits = 31; /* aacraid limitation */ - BUG_ON(HYPERVISOR_memory_op( - XENMEM_increase_reservation, &reservation) != 1); + reservation.address_bits = address_bits; + if (HYPERVISOR_memory_op(XENMEM_increase_reservation, + &reservation) != 1) + goto fail; /* 3. Map the new extent in place of old pages. */ for (i = 0; i < (1<> PAGE_SHIFT, 1UL << order); balloon_unlock(flags); + + return 0; + + fail: + reservation.extent_order = 0; + reservation.address_bits = 0; + + for (i = 0; i < (1<>PAGE_SHIFT)+i); + phys_to_machine_mapping[(__pa(vstart)>>PAGE_SHIFT)+i] = mfn; + } + + flush_tlb_all(); + + balloon_unlock(flags); + + return -ENOMEM; } void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/mm/pgtable.c b/linux-2.6-xen-sparse/arch/xen/i386/mm/pgtable.c index 3af8e92144..442ee8da14 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/mm/pgtable.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/mm/pgtable.c @@ -279,8 +279,9 @@ void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused) unsigned long flags; #ifdef CONFIG_X86_PAE - /* this gives us a page below 4GB */ - xen_create_contiguous_region((unsigned long)pgd, 0); + /* Ensure pgd resides below 4GB. */ + int rc = xen_create_contiguous_region((unsigned long)pgd, 0, 32); + BUG_ON(rc); #endif if (!HAVE_SHARED_KERNEL_PMD) diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/skbuff.c b/linux-2.6-xen-sparse/arch/xen/kernel/skbuff.c index e1cd013e24..cc13bd2cef 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/skbuff.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/skbuff.c @@ -79,8 +79,10 @@ static void skbuff_ctor(void *buf, kmem_cache_t *cachep, unsigned long unused) while (skbuff_order_cachep[order] != cachep) order++; + /* Do our best to allocate contiguous memory but fall back to IOMMU. */ if (order != 0) - xen_create_contiguous_region((unsigned long)buf, order); + (void)xen_create_contiguous_region( + (unsigned long)buf, order, 0); scrub_pages(buf, 1 << order); } diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypervisor.h b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypervisor.h index 06015e6ccb..09517d24ae 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypervisor.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypervisor.h @@ -129,8 +129,11 @@ void xen_invlpg_mask(cpumask_t *mask, unsigned long ptr); #define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var) #endif /* linux < 2.6.0 */ -void xen_create_contiguous_region(unsigned long vstart, unsigned int order); -void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order); +/* Returns zero on success else negative errno. */ +int xen_create_contiguous_region( + unsigned long vstart, unsigned int order, unsigned int address_bits); +void xen_destroy_contiguous_region( + unsigned long vstart, unsigned int order); #include -- 2.30.2